require("common")

layout = {
	new = function(rows, cols)
		local function split(str)
			assert(type(str) == "string")
			return str:split(",")
		end
		local self = { rows = split(rows), cols = split(cols), handlers = {} }
		setmetatable(self, { __index = layout })
		return self
	end,
	
	counts = function(self)
		return #(self.rows), #(self.cols)
	end,
	
	size = function(self, width, height)
		local function parse(value)
			assert(type(value) == "string")
			if value == "*" then return nil, nil, true end
			if value:endsWith("%") then return nil, tonumber(value:sub(1, #value - 1)), nil end
			return tonumber(value), nil, nil
		end
		local function rel(value, total, length)
			if total == 0 then return 0 end
			return (value / total) * length
		end
		local function sizes(values, length)
			local abstotal, perctotal, isrest = 0, 0, false
			for n, v in pairs(values) do
				local abs, perc, rest = parse(v)
				if abs then abstotal = abstotal + abs end
				if perc then perctotal = perctotal + perc end
				if rest then
					assert(not isrest)
					isrest = true
				end
			end
			local abslength, perclength, restperc 
			if abstotal < length then
				abslength = abstotal
				perclength = length - abstotal
				if isrest then
					if perctotal < 100 then
						restperc = 100 - perctotal
						perctotal = 100
					else
						restperc = 0
					end
				end
			else
				abslength = length
				perclength = 0
				restperc = 0
			end
			local ret = {}
			for n, v in pairs(values) do
				local value
				local abs, perc, rest = parse(v)
				if abs then value = rel(abs, abstotal, abslength) end
				if perc then value = rel(perc, perctotal, perclength) end
				if rest then value = rel(restperc, perctotal, perclength) end
				ret[n] = value
			end
			return ret
		end
		self.rowsizes = sizes(self.rows, height)
		self.colsizes = sizes(self.cols, width)
		self.width = width
		self.height = height
	end,
	
	cell = function(self, row, col, rowcount, colcount)
		if rowcount == nil then rowcount = 1 end
		if colcount == nil then colcount = 1 end
		assert((col >= 1) and (col + colcount - 1 <= #(self.colsizes)))
		assert((row >= 1) and (row + rowcount - 1 <= #(self.rowsizes)))
		local function sizes(lengths, count, skip)
			local ret = 0
			for i = 1, count do ret = ret + lengths[skip + i] end
			return ret
		end
		local x = sizes(self.colsizes, col - 1, 0)
		local y = sizes(self.rowsizes, row - 1, 0)
		local w = sizes(self.colsizes, colcount, col - 1)
		local h = sizes(self.rowsizes, rowcount, row - 1)
		return x, y, w, h
	end,
	
	set = function(self, loc, handler)
		assert(type(loc) == "string", "Loc must be a string")
		assert(type(handler) == "function", "Handler must be a function")
		self.handlers[loc] = handler
	end,
	
	render = function(self, handler)
		if handler ~= nil then
			assert(type(handler) == "function", "Handler must be a function or nil")
			local rows, cols = self:counts()
			for row = 1, rows do
				for col = 1, cols do
					local x, y, w, h = self:cell(row, col)
					handler(row, col, x, y, w, h)
				end
			end
			return
		end
		for loc, handler in pairs(self.handlers) do
			local lt = {}
			loc:gsub("^(%d-):(%d-)x(%d-)x(%d-)$", function(col, row, width, height)
				lt.col = tonumber(col)
				lt.row = tonumber(row)
				lt.width = tonumber(width)
				lt.height = tonumber(height)
			end)
			loc:gsub("^(%d-):(%d-)$", function(col, row)
				lt.col = tonumber(col)
				lt.row = tonumber(row)
				lt.width = 1
				lt.height = 1
			end)
			assert(type(lt.col) == "number" and type(lt.row) == "number" and type(lt.width) == "number" and type(lt.height) == "number", string.format("Wrong format of handler key %q", loc))
			handler(loc, self:cell(lt.row, lt.col, lt.height, lt.width))
		end
	end
}


